﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Remoting.Messaging;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace WindowsFormsApp1
{
    public class Tag
    {
        delegate OperateResult<Storage> ReadData(string address);

        delegate OperateResult WriteData(Storage value);

        public delegate void ValueChanged();

        public ValueChanged OnValueChanged;

        ReadData _readData;

        WriteData _writeData;

        private Storage _value;

        public int ID { get; set; }
        public string Name { get; set; }
        //public TypeCode TagType { get; set; }
        public string Description { get; set; }

        public IDriver Drive { get; set; }

        public DataType VarType { get; set; }

        public string Address { get; set; }

        public ushort StringLength { get; set; }

        public TagRWType RWType { get; set; } = TagRWType.ReadAndWrite;

        public int TimeSpan { get; set; } = 1000;

        public Storage Value
        {
            get { return _value; }
            set
            {
                if (!_value.Equals(value))
                {
                    _value = value;
                    _writeData.BeginInvoke(value, ar => { OperateResult result = _writeData.EndInvoke(ar); }, null);
                    //_writeData?.Invoke(value);
                }
            }
        }
        public Tag(int id, string name, string address, DataType varType)
        {
            ID = id;
            Name = name;
            Address = address;
            VarType = varType;
            _readData = Read;
            _writeData = Write;
            //_readData.BeginInvoke(Address, ReadCallback, null);
        }

        public OperateResult<Storage> Read(string address)
        {
            if (!Drive.IsConnected) return null;
            Storage storage = Storage.Empty;

            //switch (Type.GetTypeCode(t))
            //{
            //    case TypeCode.Empty:
            //        return null;
            //    case TypeCode.Boolean:
            //        storage.Boolean = Drive.ReadBool(Address).Content;
            //        return new OperateResult<Storage>()
            //        {
            //            Content = storage,
            //            IsSuccess = Drive.ReadBool(Address).IsSuccess,
            //            Message = Drive.ReadBool(Address).Message
            //        };
            //    case TypeCode.Int16:
            //        storage.Int16 = Drive.ReadInt16(Address).Content;
            //        return new OperateResult<Storage>()
            //        {
            //            Content = storage,
            //            IsSuccess = Drive.ReadInt16(Address).IsSuccess,
            //            Message = Drive.ReadInt16(Address).Message
            //        };

            //    case TypeCode.Int32:
            //        storage.Int32 = Drive.ReadInt32(Address).Content;
            //        return new OperateResult<Storage>()
            //        {
            //            Content = storage,
            //            IsSuccess = Drive.ReadInt32(Address).IsSuccess,
            //            Message = Drive.ReadInt32(Address).Message
            //        };

            //    case TypeCode.Single:
            //        storage.Single = Drive.ReadFloat(Address).Content;
            //        return new OperateResult<Storage>()
            //        {
            //            Content = storage,
            //            IsSuccess = Drive.ReadFloat(Address).IsSuccess,
            //            Message = Drive.ReadFloat(Address).Message
            //        };
            //    default:
            //        return null;

            switch (VarType)
            {
                case DataType.BOOL:
                    storage.Boolean = Drive.ReadBool(Address).Content;
                    return new OperateResult<Storage>()
                    {
                        Content = storage,
                        IsSuccess = Drive.ReadBool(Address).IsSuccess,
                        Message = Drive.ReadBool(Address).Message
                    };
                case DataType.SHORT:
                    storage.Int16 = Drive.ReadInt16(Address).Content;
                    return new OperateResult<Storage>()
                    {
                        Content = storage,
                        IsSuccess = Drive.ReadBool(Address).IsSuccess,
                        Message = Drive.ReadBool(Address).Message
                    };
                //case DataType.WORD:
                //    break;
                //case DataType.DWORD:
                //    break;
                //case DataType.INT:
                //    break;
                //case DataType.FLOAT:
                //    break;
                //case DataType.SYS:
                //    break;
                //case DataType.STR:
                //    break;
                default:
                    return null;
            }
        }


        private void ReadCallback(IAsyncResult iar)
        {
            AsyncResult ar = (AsyncResult)iar;
            ReadData del = (ReadData)ar.AsyncDelegate;
            try
            {
                OperateResult<Storage> result = del.EndInvoke(ar);
                if (result != null && result.IsSuccess)
                {
                    if (!_value.Equals(_value))
                    {
                        _value = result.Content;
                        OnValueChanged?.Invoke();
                    }
                }
            }
            catch (Exception ex)
            {

            }

            Thread.Sleep(1000);
            del.BeginInvoke(Address, ReadCallback, null);
        }

        public void WriteTest(Storage value)
        {
            _writeData.BeginInvoke(value, ar => { OperateResult result = _writeData.EndInvoke(ar); }, null);
        }

        private OperateResult Write(Storage value)
        {
            //switch (Type.GetTypeCode(t))
            //{
            //    case TypeCode.Empty:
            //        return new OperateResult() { Message = "" };
            //    case TypeCode.Boolean:
            //        return Drive.Write(Address, Convert.ToBoolean(value));
            //    case TypeCode.Byte:
            //        return Drive.Write(Address, Convert.ToByte(value));
            //    case TypeCode.Int16:
            //        return Drive.Write(Address, Convert.ToInt16(value));
            //    case TypeCode.UInt16:
            //        return Drive.Write(Address, Convert.ToUInt16(value));
            //    case TypeCode.Int32:
            //        return Drive.Write(Address, Convert.ToInt32(value));
            //    case TypeCode.UInt32:
            //        return Drive.Write(Address, Convert.ToUInt32(value));
            //    case TypeCode.Int64:
            //        return Drive.Write(Address, Convert.ToInt64(value));
            //    case TypeCode.UInt64:
            //        return Drive.Write(Address, Convert.ToUInt64(value));
            //    case TypeCode.Single:
            //        return Drive.Write(Address, Convert.ToSingle(value));
            //    case TypeCode.Double:
            //        return Drive.Write(Address, Convert.ToDouble(value));
            //    case TypeCode.String:
            //        return Drive.Write(Address, Convert.ToString(value));
            //    default:
            //        return new OperateResult() { Message = "" };
            //}
            switch (VarType)
            {
                case DataType.BOOL:
                    return Drive.Write(Address, value.Boolean);
                case DataType.SHORT:
                    return Drive.Write(Address, value.Int16);
                default:
                    return new OperateResult() { Message = "" };
            }
        }
    }
}
